<template>
    <div i="data-table">
        <div class="table-header" >
            <div class="table-btns" >
                <Btns :data="btns" justify="flex-start" v-if="btns.length" />
            </div>
            <div class="setting-list" v-if="showConfig">
                <a-popover
                    class="setting-item"
                    placement="bottom"
                    trigger="click">
                    <template slot="content">
                        <div class="setting-menu-item" @click="initColumn"><a-icon type="reload" />重置</div>
                        <template v-for="(item, index) in columns">
                            <div class="setting-menu-item" :key="index" v-if="$util.isShow(item.show)">
                                <a-checkbox
                                    v-model="item.show"
                                    :disabled="item.show && (columns.filter(col => col.show).length === 2)">
                                    {{item.label}}
                                </a-checkbox>
                            </div>
                        </template>
                    </template>
                    <a-tooltip title="列设置" placement="top">
                        <a-icon type="setting" />
                    </a-tooltip>
                </a-popover>
                <a-tooltip title="刷新" placement="top">
                    <a-icon type="reload" @click="refresh" />
                </a-tooltip>
            </div>
        </div>
        <a-table
            ref="table"
            :columns="showColumns"
            :dataSource="tableData"
            :bordered="border"
            :defaultExpandAllRows="defaultExpandAllRows?defaultExpandAllRows:false"
            size="middle"
            :rowKey="rowKey ? rowKey : (record,index)=> index"
            :loading="loading"
            :rowSelection="rowSelection"
            :scroll="scroll"
            :childrenColumnName="childrenColumnName"
            :indentSize="indentSize"
            :align="align"
            @expand="handleExpand"
            :pagination="pagination">
            <template slot="title" >
                <slot name="title"></slot>
            </template>
            <template slot-scope="value, record, idx" :slot="item.prop" v-for="(item, index) in showColumns">
                <div :key="index" class="flex-inline">
                    <!-- 插槽 -->
                    <template v-if="item.slot">
                        <slot :name="item.prop" :row="record" :index="idx"></slot>
                    </template>
                    <!-- 跳转路由 -->
                    <template v-else-if="item.type === 'router'">
                        <!-- 跳转路由 -->
                        <router-link
                            :to="Object.keys(item.query || {}).reduce((a, b) => { a.query[b] = record[b] || item.query[b]; return a }, { path: typeof item.path === 'function' ? item.path(record,  scope.$index) : item.path, query: {}})"
                            class="link-btn"
                            tag="a">
                            {{item.map ? item.map[record[item.prop]] : record[item.prop]}}
                        </router-link>
                    </template>
                    <!-- 自定义内容 -->
                    <template v-else-if="item.custom">
                        {{item.custom(record)}}
                    </template>
                    <!-- 价钱 -->
                    <template v-else-if="item.type === 'price'">
                        <span>{{(value || value === 0) ? inputNumberFormatter(value, 'price') : '--'}}</span>
                    </template>
                    <!-- 头像 -->
                    <template v-else-if="item.type === 'avatar'">
                        <a-avatar :src="value" />
                    </template>
                    <!-- 有事件点击 -->
                    <template v-else-if="item.type === 'event'">
                        <span class="blue-class" @click="$emit('handleEvent', record)">{{record[item.prop]}}</span>
                    </template>
                    <!-- 状态 -->
                    <template v-else-if="item.type === 'status'">
                        <span
                            class="table-status"
                            :class="value === item.flag ? 'success' : 'fail'">
                            {{value === item.flag ? item.successTxt : item.failTxt}}
                        </span>
                    </template>
                    <!-- tag标签 -->
                    <template v-else-if="item.type === 'tag'">
                        <a-tag v-for="tag in item.tags" :key="tag.name" :color="tag.color">{{ tag.name }}</a-tag>
                    </template>
                    <!-- 开关 -->
                    <template v-else-if="item.type === 'switch'">
                        <a-switch
                            v-model="record[item.prop]"
                            :disabled="$util.isDisabled(item.disabled)"
                            @change="item.callback && item.callback(record, idx)" />
                    </template>
                    <!-- 开关 -->
                    <template v-else-if="item.type === 'switch2' && record.typeSettings && record.typeSettings.length==0 || item.type === 'switch2' && !record.typeSettings">
                        <a-switch
                            v-model="record[item.prop]"
                            :disabled="$util.isDisabled(item.disabled)"
                            @change="item.callback && item.callback(record, idx)" />
                    </template>
                    <!-- 数字输入框 -->
                    <template v-else-if="item.type === 'inputNumber'" class="column-flex">
                        <a-input-number
                            v-model="record[item.prop]"
                            :formatter="value => inputNumberFormatter(value, item.cat, item.formatter, item.pre)"
                            :parser="value => inputNumberParser(value, item.cat, item.parser)"
                            :step="item.step || 1"
                            :precision="item.precision || 0"
                            :min="item.min || 0"
                            :max="typeof item.max === 'function' ? item.max(record) : (item.max || Infinity)"
                            :disabled="$util.isDisabled(item.disabled)"
                            @change="item.callback && item.callback(record, index)" />
                    </template>
                    <!-- 输入框 -->
                    <template v-else-if="item.type === 'input'">
                        <a-input
                            v-model="record[item.prop]"
                            :placeholder="item.placeholder"
                            :disabled="$util.isDisabled(item.disabled)"
                            @change="item.callback && item.callback(record, index)" :maxLength="item.maxLength"/>
                    </template>
                    <!-- 星级 -->
                    <template v-else-if="item.type === 'rate'">
                        <a-rate
                            v-model="record[item.prop]"
                            :allow-half="item.half" />
                    </template>
                    <!-- 下拉菜单 -->
                    <template v-else-if="item.type === 'select'">
                        <a-select
                            v-model="record[item.prop]"
                            :allowClear="item.clearable"
                            :show-search="item.filterable"
                            :placeholder="item.placeholder"
                            :style="{width: item.width ? item.width + 'px' : '100%'}"
                            :disabled="$util.isDisabled(item.disabled)"
                            @change="(val) => item.callback && item.callback(val, idx)"
                        >
                            <a-select-option
                                v-for="option in item.options"
                                :key="option[item.valueKey || 'value']"
                                :value="option[item.valueKey || 'value']">
                                {{option[item.labelKey || 'label']}}
                            </a-select-option>
                        </a-select>
                    </template>
                    <!-- 下拉菜单2 -->
                    <template v-else-if="(item.type === 'select2' && record.typeSettings && record.typeSettings.length==0 && !record.isFalg) || item.type === 'select2' && !record.typeSettings && !record.isFalg">
                        <a-select
                            v-model="record[item.prop]"
                            :allowClear="item.clearable"
                            :show-search="item.filterable"
                            :placeholder="item.placeholder"
                            :style="{width: item.width ? item.width + 'px' : '100%'}"
                            :disabled="$util.isDisabled(item.disabled)"
                            @change="(val) => item.callback && item.callback(val, record)"
                        >
                            <a-select-option
                                v-for="option in item.options"
                                :key="option[item.valueKey || 'value']"
                                :value="option[item.valueKey || 'value']">
                                {{option[item.labelKey || 'label']}}
                            </a-select-option>
                        </a-select>
                    </template>
                    <!-- 输入框 -->
                    <template v-else-if="(item.type === 'select2' && record.typeSettings && record.typeSettings.length==0 && record.isFalg) || item.type === 'select2' && !record.typeSettings && record.isFalg">
                        <a-input v-model="record[item.prop]" :placeholder="item.placeholder" :disabled="$util.isDisabled(item.disabled)" @blur="(val) =>item.callback && item.callback(val, record)" :maxLength="item.maxLength"/>
                    </template>
                    <!-- 操作 -->
                    <template v-else-if="item.type === 'action'">
                        <div class="operation">
                            <template v-for="(child, index) in item.template">
                                <div
                                    v-if="$util.isShow(child.show, record)"
                                    :key="index"
                                    v-permission="child.permission"
                                >
                                    <!-- 跳转路由 -->
                                    <router-link
                                        v-if="child.tag === 'router-link'"
                                        :to="Object.keys(child.query || {}).reduce((a, b) => { a.query[b] = record[b] || child.query[b]; return a }, { path: typeof child.path === 'function' ? child.path(record,  scope.$index) : child.path, query: {}})"
                                        class="link-btn"
                                        tag="a">
                                        {{child.map ? child.map[record[child.prop]] : child.text}}
                                    </router-link>
                                    <!-- 普通按钮 -->
                                    <a
                                        v-if="child.tag === 'a' && !child.confirm"
                                        href="javascript:;"
                                        class="link-btn"
                                        @click.stop="child.callback && child.callback(record, index)">
                                        {{child.map ? child.map[record[child.prop]] : child.text ? child.text : (record[child.prop] === child.flag) ? child.actText : child.inactText}}
                                    </a>
                                    <!-- 带二次确认的按钮 -->
                                    <a-popconfirm
                                        v-if="child.tag === 'a' && child.confirm"
                                        :title="child.confirmTxt || '确定执行该操作吗？'"
                                        @confirm="child.confirm(record, index)">
                                        <a
                                            href="javascript:;"
                                            class="link-btn">
                                            {{child.map ? child.map[record[child.prop]] : child.text ? child.text : (record[child.prop] === child.flag) ? child.actText : child.inactText}}
                                        </a>
                                    </a-popconfirm>
                                </div>
                            </template>
                        </div>
                    </template>
                    <template v-else-if="item.type2 === 'action2'">
                        <template v-if="record.typeSettings">
                            <div class="operation">
                                <template v-for="(child, index) in item.template" >
                                    <div
                                        v-if="$util.isShow(child.show, record)"
                                        :key="index"
                                        v-permission="child.permission"
                                    >
                                        <!-- 跳转路由 -->
                                        <router-link
                                            v-if="child.tag === 'router-link' && index==1"
                                            :to="Object.keys(child.query || {}).reduce((a, b) => { a.query[b] = record[b] || child.query[b]; return a }, { path: typeof child.path === 'function' ? child.path(record,  scope.$index) : child.path, query: {}})"
                                            class="link-btn"
                                            tag="a">
                                            {{child.map ? child.map[record[child.prop]] : child.text}}
                                        </router-link>
                                        <!-- 普通按钮 -->
                                        <a
                                            v-if="child.tag === 'a' && !child.confirm && index==0"
                                            href="javascript:;"
                                            class="link-btn"
                                            @click.stop="child.callback && child.callback(record, index)">
                                            {{child.map ? child.map[record[child.prop]] : child.text ? child.text : (record[child.prop] === child.flag) ? child.actText : child.inactText}}
                                        </a>
                                    </div>
                                </template>
                            </div>

                        </template>
                        <template v-else>
                            <div class="operation">
                                <template v-for="(child, index) in item.template" >
                                    <div
                                        v-if="$util.isShow(child.show, record)"
                                        :key="index"
                                        v-permission="child.permission"
                                    >
                                        <a
                                            v-if="(child.tag === 'a' && index==3) || (child.tag === 'a' && index==2)"
                                            href="javascript:;"
                                            class="link-btn"
                                            @click.stop="child.callback && child.callback(record, index)">
                                            {{child.map ? child.map[record[child.prop]] : child.text ? child.text : (record[child.prop] === child.flag) ? child.actText : child.inactText}}
                                        </a>
                                    </div>
                                </template>
                            </div>

                        </template>
                    </template>
                    <!-- 默认 -->
                    <template v-else>
                        <a-tooltip placement="top" v-if="item.hidden">
                            <template slot="title">
                                <div>{{item.map ? item.map[record[item.prop]] : $util.isBlank(record[item.prop]) ? '--' : record[item.prop]}}</div>
                            </template>
                            <div class="hidden">{{item.map ? item.map[record[item.prop]] : $util.isBlank(record[item.prop]) ? '--' : record[item.prop]}}</div>
                        </a-tooltip>
                        <div v-else>{{item.map ? item.map[record[item.prop]] : $util.isBlank(record[item.prop]) ? '--' : record[item.prop]}}</div>
                    </template>
                </div>
            </template>
            <!-- 展开行 -->
            <template v-if="expand" #expandedRowRender="record, index">
                <slot name="expand" :data="record" :index="index"></slot>
            </template>
        </a-table>
        <slot></slot>
    </div>
</template>

<script>
export default {
    name: 'DataTable',
    props: {
        defaultExpandAllRows: {
            type: Boolean,
            default: false
        },
        scroll: {
            type: Object,
            default: () => ({})
        },
        rowKey: {
            type: String,
            default: ''
        },
        expand: {
            type: Boolean,
            default: false
        },
        align: {
            type: String,
            default: 'left'
        },
        // 表格数据
        tableData: {
            type: Array,
            default: () => []
        },
        tableColumn: {
            type: Object,
            default: () => ({})
        },
        // 是否有边框
        border: {
            type: Boolean,
            default: false
        },
        showQuickJumper: {
            type: Boolean,
            default: true
        },
        btns: {
            type: Array,
            default: () => []
        },
        showConfig: {
            type: Boolean,
            default: true
        },
        rowSelection: {
            type: Object,
            default: null
        },
        pageConfig: {
            type: Object,
            default: null
        },
        childrenColumnName: {
            type: String,
            default: 'children'
        },
        indentSize: {
            type: Number,
            default: 5
        }
    },
    data () {
        return {
            columns: [],
            loading: false
        }
    },
    computed: {
        showColumns () {
            return this.columns.filter(item => item.show)
        },
        pagination () {
            return this.pageConfig ? {
                size: 'small',
                showQuickJumper: true,
                current: 1,
                pageSize: 10,
                total: 0,
                showTotal: total => `总共 ${total} 条数据`,
                ...this.pageConfig
            } : false
        }
    },
    methods: {
        initColumn () {
            this.columns = Object.entries(this.tableColumn)
                .map(item => Object.assign({ prop: item[0] }, item[1]))
                .map(item => { item.show = true; return item })
                .map(item => ({
                    ...item,
                    title: item.label,
                    align: this.align,
                    dataIndex: item.prop === 'action' ? undefined : item.prop,
                    // fixed: item.prop === 'action' && (item.fixed === undefined ? 'right' : item.fixed),
                    key: item.prop,
                    type: item.type ? item.type : item.prop === 'action' ? 'action' : '',
                    type2: item.type2 ? item.type2 : item.prop === 'action2' ? 'action2' : '',
                    scopedSlots: { customRender: item.prop }
                }))
        },
        handleExpand (expanded, record) {
            this.$emit('expand', expanded, record)
        },
        handleCurrentChange (val) {
            this.$emit('changeCurrent', val)
        },
        handleRowClick (row, column, event) {
            this.$emit('rowClick', row, column, event)
        },
        handleLoad (tree, treeNode, resolve) {
            this.$emit('load', tree, treeNode, resolve)
        },
        replaceProp (obj, str, prehook) {
            if (prehook) {
                return prehook(obj[str.match(/[a-zA-Z0-9_]+(?=\})/)[0]], str.match(/[a-zA-Z0-9_]+(?=\})/)[0], obj)
            }
            return obj[str.match(/[a-zA-Z0-9_]+(?=\})/)[0]]
        },
        showPower (value = 0) {
            let permissions = JSON.parse(localStorage.getItem('permissions') || '{}')
            if (typeof value === 'number') {
                if (value === 0) return true;
                return permissions[value].show_menu
            }
            if (Array.isArray(value)) {
                let allPass = value.map(item => item.permission || 0).some(item => value > 0 ? permissions[item].show_menu : true)
                return allPass
            }
        },
        refresh () {
            this.loading = true
            this.$emit('refresh')
        },
        inputNumberFormatter (value, cat, cb, pre = '￥') {
            switch (cat) {
                case 'price':
                    if (pre) {
                        return `${pre} ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
                    }
                    return value.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
                case 'percent':
                    return `${value}${pre}`
                default:
                    cb && cb(value)
                    return value
            }
        },
        inputNumberParser (value, cat, cb) {
            switch (cat) {
                case 'price':
                    return value.replace(/\$\s?|(,*)/g, '')
                case 'percent':
                    return value.replace(/%\s?|(,*)/g, '')
                default:
                    cb && cb(value)
                    return value
            }
        }
    },
    watch: {
        tableData () {
            this.loading = false
        },
        tableColumn: {
            handler () {
                this.initColumn()
            },
            immediate: true
        }
    }
}
</script>
<style lang="scss">
    [i="data-table"] {
        width: 100%;
        overflow: hidden;
        // 右侧操作栏fixed后, 对column的隐藏显示有几率出现操作栏对不齐的bug, 所以固定top为表头的高度
        // .el-table__fixed-right .el-table__fixed-body-wrapper {
        //     top: 36px !important;
        //     z-index: 999 !important;
        // }
        .ant-table-body { overflow-x: auto}
        .table-header {
            width: 100%;
            display: flex;
            align-items: center;
            justify-content: space-between;
            // margin-bottom: 20px;
            .table-btns {
                flex: 1;
            }
            .setting-list {
                display: flex;
                align-items: center;
                .el-divider--vertical {
                    margin-left: 20px;
                    margin-right: 0;
                }
                .setting-item {
                    width: 20px;
                    height: 20px;
                    display: flex;
                    margin: 0 20px;
                }
                i {
                    font-size: 20px;
                    cursor: pointer;
                }
            }
        }
        .avatarImg {
            width: 50px;
            height: 50px;
            border-radius: 4px;
            overflow: hidden;
        }
        .blue-class{
            cursor: pointer;
            color: #2572fa;
        }
        .coverImg .el-image,
        .avatarImg .el-image {
            width: 100%;
            height: 100%;
        }
        .coverImg {
            width: 160px;
            height: 98px;
        }
        .table-status {
            position: relative;
            left: .6rem;
            &.success::before {
                content: '';
                width: 6px;
                height: 6px;
                position: absolute;
                left: -10px;
                top: 50%;
                transform: translateY(-50%);
                border-radius: 50%;
                background: #a3df85;
            }
            &.fail::before {
                content: '';
                width: 6px;
                height: 6px;
                position: absolute;
                left: -10px;
                top: 50%;
                transform: translateY(-50%);
                border-radius: 50%;
                background: red;
            }
        }
        .column-flex {
            display: flex;
            align-items: center;
            .prefix {
                margin-right: 4px;
            }
        }
        .operation {
            display: flex;
            flex-wrap: wrap;
            > div {
                // position: relative;
                display: flex;
                align-items: center;
                padding: 0 10px;
                line-height: 1;
                // margin-bottom: 5px;
                line-height: 21px;
                &::after {
                    position: absolute;
                    content: '';
                    width: 1px;
                    height: 14px;
                    background: #dfe7ec;
                    right: 0;
                    top: 50%;
                    transform: translateY(-50%);
                }
                &:first-child {
                    padding-left: 0;
                }
                &:last-child {
                    &::after {
                        display: none;
                    }
                }
            }
        }
    }
    .setting-menu-item {
        line-height: 35px;
        padding: 0 10px;
        i {
            margin-right: 10px;
        }
        &:first-child {
            width: 200px;
            border-bottom: 1px solid #f0f0f0;
            margin-left: -12px;
            padding-left: 20px;
            &:hover {
                cursor: pointer;
                color: #409EFF;
            }
        }
    }
.hidden {
    overflow: hidden;
    white-space: nowrap; /*不换行*/
    text-overflow: ellipsis; /*省略号*/
}
.flex-inline{
    display: inline-block;
    width: 100%;
}
</style>
